/*
 * lab3q18.c
 *
 *  Created on: Mar 5th, 2011
 *      Author: stellarhopper
 */

/*
 * PROGRAM DESCRIPTION
 *
 * Count external events on counter 0.
 *
 * Provide Menu Options for:
 *
 * 	- Clear Counter 0
 * 	- Run Counter 0
 *	- Stop Counter 0
 * 	- Run PWM
 * 	- Stop PWM
 *	- Read Counter 0 and print value
 *	- Enter Idle mode
 *	- Enter Power Down mode
 *	- Auto/Manual Toggle of count event
 */

/*
 * COMPILER FLAGS
 * sdcc -c --debug -mmcs51 --std-sdcc99 --model-large
 *
 * LINKER FLAGS
 * sdcc --debug -mmcs51 --code-loc 0x0000 --code-size 0x8000 --xram-loc 0x0000 --xram-size 0x8000 --model-large --out-fmt-ihx
 *
 * USAGE SPECIFICATIONS:
 * Baud rate - 57600
 */


/*==============================================INCLUDES=========================================*/
#include <at89c51ed2.h>  //also includes 8052.h and 8051.h
#include <mcs51reg.h>
#include <stdio.h>
#include <stdlib.h>

/*==============================================DEFINES==========================================*/
#define TRUE 1
#define FALSE 0
#define HEAP_SIZE 1800   				// size must be smaller than available XRAM
#define EC_CRIT -1						//currently unused
#define SILENT 1
#define VERBOSE 0
#define ON 1
#define OFF 0


/*==============================================GLOBALS==========================================*/

int togEvent = ON;

enum RETCODE{							//retcodes/parameter flags for all functions
	OK = 0
};

/*=========================================FUNCTION PROTOTYPES===================================*/

void putchar (char c);
char getchar (void);
int putstr (char *s);
int getstr (char *s);
void serialInit(int);
void clearScr(void);
void myDelay(int j);
void initAll(void);

void initPwm(void);
void printMenu(void);

/*=========================================FUNCTION DEFINITIONS===================================*/

/*
* NAME :            _sdcc_external_startup
*
* DESCRIPTION :     Will run before main(). Used to initialize registers etc. as required
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	AUXR
*
* OUTPUTS :
*       GLOBALS:	AUXR
*       RETURN:		-
*
*/

_sdcc_external_startup() {

	AUXR |= 0x0C;
	return 0;
}

/*
* NAME :            putchar
*
* DESCRIPTION :     print 1 character to serial port
*
* INPUTS :
*       PARAMETERS:	char c
*		GLOBALS:	SCON
*
* OUTPUTS :
*       GLOBALS :	SBUF, TI
*       RETURN :	-
*
* PROCESS :
*                   [1]	Wait for port to be ready
* 					[2]	Print char and clear TI
*/

void putchar (char c) {

	while ((SCON & 0x02) == 0);    				// wait for TX ready, spin on TI
	SBUF = c;  									// load serial port with transmit value
	TI = 0;  									// clear TI flag
}

/*
* NAME :            getchar
*
* DESCRIPTION :     get 1 character from serial port
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	SCON
*
* OUTPUTS :
*       GLOBALS :	SBUF, RI
*       RETURN :	SBUF - character received
*
* PROCESS :
*                   [1]	Wait for character to be received
* 					[2]	Clear RI
*					[3] Return character
*/

char getchar () {

    while ((SCON & 0x01) == 0);  				// wait for character to be received, spin on RI
	RI = 0;										// clear RI flag
	return SBUF;  								// return character from SBUF
}

/*
* NAME :            putstr
*
* DESCRIPTION :     Print a string to serial port
*
* INPUTS :
*       PARAMETERS:	char *s
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	Number of characters transmitted
*
* PROCESS :
*                   [1]  Transmit characters till oxoo (NULL) is encountered
*/

int putstr (char *s) {

	int i = 0;
	while (*s){									// output characters until NULL found
		putchar(*s++);
		i++;
	}
	//putchar('\n\r');
	return i+1;
}

/*
* NAME :            getstr
*
* DESCRIPTION :     Get a string from serial port
*
* INPUTS :
*       PARAMETERS:	char *s
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: char *s
*       GLOBALS :	-
*       RETURN :	i - number of characters read
*
* PROCESS :
*                   [1]  Accept characters till 0x0D encountered (CR)
*					[2]	 Store starting at given location (*s)
*
* NOTES :           Is not safe from buffer overrun. Assumes valid memory available for all characters input.
*					Can be substituted with gets() which is equally unsafe but I wrote this so am going with it :)
*/

int getstr (char *s) {

	int i = 0;
	do {
		s[i] = getchar();
		putchar(s[i]);
		i++;
	} while(s[i-1] != 0x0D);  					//0x0D is <CR>
	s[i-1] = 0x00;								//replace <CR> with NULL (0x00)
	putchar('\n\r');
	return (i-1);
}

/*
* NAME :            serialInit
*
* DESCRIPTION :     Initialize the serial port
*
* INPUTS :
*       PARAMETERS:	int br (BAUD RATE)
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	PCON, SCON, TMOD, TH1, TR1, TI
*       RETURN :	-
*
*
* NOTES :  Baud rate is supplied as 0xFF for 56700 etc
*/

void serialInit(int br) {
/*
	PCON |= 0x80;					//SMOD1 = 1
	SCON = 0x50;					   //uart in mode 1 (8 bit), REN=1
	BDRCON &=0xEC;                //BRR=0; SRC=0;
	BDRCON |=0x0E;                //TBCK=1;RBCK=1; SPD=1
	BRL=0xFD;                     //115200 Bds at 11.059MHz
	EA = 1; 						     // Enable serial interrupt
	BDRCON |= 0x10;                //Baud rate generator run
*/

	PCON |= 0x80;								//configure uart, fast baud
	SCON = 0x50;                   			 	//SCON: mode 1, 8-bit UART, enable rcvr
	TMOD |= 0x20;                   			//TMOD: timer 1, mode 2, 8-bit reload
	TH1 = br;                   				//TH1:  reload value for baudrate
						//TODO: get load value from real-life baudrate values -- lkup?
	TR1   = 1;                      			//TR1:  timer 1 run
	TI    = 1;                      			//TI:   set TI to send first char of UART

}

/*
* NAME :            initAll
*
* DESCRIPTION :     Reset global variables to initial values
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	-
*/

void initAll() {

	int i = 0;

	EA = 1;
	TMOD |= 0x05;               //setting timer0 in counter mode
	togEvent = ON;
	P1_5 = ON;
}

void initPwm() {
	CCAPM0 = 0x42;            	// enabling PWM for module 2
	CCAPM1 = 0x42;           	// enabling PWM for module 3
	CCAP0H = 0x66;            	// (60% DUTY CYCLE)  PORT P1.3 102
	CCAP1H = 0x99;           	// (40% DUTY CYCLE)  PORT P1.4 153
}

/*
* NAME :            clearScr
*
* DESCRIPTION :     Clears and resets the VT100 terminal
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	-
*
*
* NOTES :           Will clear the VT100 terminal by sending control sequences to reset and clear entire screen
*					Reset: ESC c
*					Clear Screen: ESC [ 2 J
*/

void clearScr() {
	printf("\033c");			//reset terminal
	printf("\033[2J");			//clear screen
}

/*
* NAME :            myDelay
*
* DESCRIPTION :     Provide a delay
*
* INPUTS :
*       PARAMETERS:	int j - empirical - j=1 ~ 1 second
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	-
*/

void myDelay(int j) {
	int i = 0;
	int cnt = 0;

	j*=100;
	while(j) {
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		j--;
	}

}

/*
* NAME :            printMenu
*
* DESCRIPTION :     prints menu
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*      
*/

void printMenu() {
	clearScr();
	printf("****************************************WELCOME********************************\n\n\r");
	putstr("	 This program can test various features of the ATMEL 89C51RC2 \n\r");
	putstr("  Press any number  between  1-9 to  choose from the different options.\n\r\n\r");
	putstr("*******************************************************************************\n\n\n\r");

	putstr("1-> Clear Counter 0 \n\r");
	putstr("2-> Run Counter 0 \n\r");
	putstr("3-> Stop Counter 0 \n\r");
	putstr("4-> Run PWM \n\r");
	putstr("5-> Stop PWM \n\r");
	putstr("6-> Read Counter 0 and print value \n\r");
	putstr("7-> Enter Idle mode \n\r");
	putstr("8-> Enter Power Down Mode \n\r\n");
	putstr("9-> Toggle Count Event (Alternatively, use SPACE) \n\r\n");

	/*if (togEvent == ON)	putstr("Event Status: ON \n\r\n");
	else if (togEvent == OFF)	putstr("Event Status: OFF \n\r\n");*/

	putstr("*******************************************************************************\n\r\n\r");
	putstr("Command > ");
}

/*
* NAME :            int1Vect
*
* DESCRIPTION :     ISR for interrupt INT1
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: -
*       GLOBALS :	-
*       RETURN :	-
*
* PROCESS :
*                   [1]  Returns immediately
*
* NOTES :           
*/

void int1Vect(void) __interrupt (IE1_VECTOR) {		 //external interrupt ISR1 routine
	return;
}

/*=========================================FUNCTION MAIN==========================================*/

void main() {

	char cmd = 0;

	serialInit(0xFF); 						//0xFF gives Baud Rate 57600
	initAll();
	clearScr();
	P1_7 = ON;

	while(1){
		printMenu();
		cmd = getchar();
		putchar(cmd);

		switch (cmd) {
			case '1':
				TH0=0;
				TL0=0;
				clearScr();
				putstr("Counter 0 Cleared! \n\r");
				myDelay(1);
				break;

			case '2':
				TR0 = 1;
				clearScr();
				putstr("Counter 0 Started! \n\r");
				putstr("Use option 9 to toggle \n\r");
				myDelay(1);
				break;

			case '3':
				TR0 = 0;
				clearScr();
				putstr("Counter 0 Stopped! \n\r");
				myDelay(1);
				break;

			case '4':
				initPwm();
				CCON =0x40;
				clearScr();
				putstr("PWM Started! \n\r");
				putstr("Output on Pins P1.3 and P1.4 \n\r");
				putstr("Press any key to continue: \n\r");
				getchar();
				break;

			case '5':
				CCON =0x00;
				clearScr();
				putstr("PWM Stopped! \n\r");
				myDelay(1);
				break;

			case '6':
				clearScr();
				printf("Count: 0x%02X%02X \n \r", TH0, TL0);
				putstr("Press any key to continue: \n\r");
				getchar();
				break;

			case '7':
				clearScr();
				putstr("Idle mode activated.\n\r");
				P1_7 = OFF;
				putstr("Use Reset or INT1 to deactivate.\n\r");
				EX1 = 1;
				PCON |= 0x01;

				EX1 = 0;
				P1_7 = ON;
				printf("Idle mode deactivated.\n\r");
				putstr("Press any key to continue: \n\r");
				getchar();
				break;

			case '8':
				clearScr();
				putstr("Power Down mode activated.\n\r");
				putstr("Use Reset or INT1 to deactivate.\n\r");
				P1_7 = OFF;
				EX1 = 1;
				PCON |= 0x02;

				EX1 = 0;
				P1_7 = ON;
				printf("Power Down mode deactivated.\n\r");
				putstr("Press any key to continue: \n\r");
				getchar();
				break;

			case ' ':
			case '9':
				//(togEvent)?(togEvent--):(togEvent++);
				//P1_5 = togEvent;
				//(togEvent)?(togEvent--):(togEvent++);
				//P1_5 = togEvent;
				P1_5 = ON;
				P1_5 = OFF;
				P1_5 = ON;
				break;

			default:
				clearScr();
				putstr("Invalid Entry, Try again! \n\r");
				myDelay(1);
		}
	}

	//putstr("\n\r\n\rCritical Error!!!\n\r");		//should never have reached here
}

